#!/usr/bin/perl -w
### make-chap.pl, initial version: 22:01 2007-11-10

use warnings;
use strict;
use Getopt::Long qw(:config gnu_getopt);

my ($total_time, $chapter_time, $output, $help);
my %options = (
    'total-time|t=s'   => \$total_time,
    'chapter-time|c=s' => \$chapter_time,
    'output|o=s'       => \$output,
    'help|h|?'         => \$help,
);
error(-1, "Please run the program with option '--help'.") unless GetOptions(%options);
usage() if $help;
# orphaned argument can be used as total time
$total_time = $ARGV[0] if (!defined($total_time) && @ARGV == 1);
error(-1, "You must specify total time.") unless defined($total_time);
# chapter time is by default 5 minutes
unless (defined($chapter_time)) {
    print STDERR ("chapter time was not defined, use default: 0:05:00.000\n");
    $chapter_time = 300;
}if (defined($output)) {
    open OUTPUT, '>', $output or error(3, "cannot open output: $output: $!");
    select OUTPUT;
}

# =====================================================================

my $total_secs   = interpret_time($total_time);
error("invalid total time format: $total_time\n") unless defined($total_secs);
my $chapter_secs = interpret_time($chapter_time);
error("invalid chapter time format: $chapter_time\n") unless defined($chapter_secs);
printf STDERR "Total   time: %s seconds (%s)\n", $total_secs, secs_to_time($total_secs);
printf STDERR "Chapter time: %s seconds (%s)\n", $chapter_secs, secs_to_time($chapter_secs);
print STDERR "\n";

print "# chapter information\n\n";
my $pointer = 0;
my $counter = 1;
while ($pointer < $total_secs) {
    printf "CHAPTER%04d=%s\n", $counter, secs_to_time($pointer);
    printf "CHAPTER%04dNAME=ch%2d\n", $counter, $counter;
    print "\n";
    $pointer += $chapter_secs;
    ++$counter;
}

# =====================================================================

close OUTPUT if defined($output);

# =====================================================================

sub usage {
    (my $PROG = $0) =~ s/.*[\\\/]//;
    print STDERR <<"EO_USAGE";
usage:
    $PROG [ OPTIONS ] -t TOTAL_TIME [ -c CHAPTER_TIME ] [ -o OUTPUT ]
options:
    -t, --total-time=TIME    specify the runtime of video
    -o, --chapter-time=TIME  specify the runtime of a chapter,
                             default is 0:05:00.000.
    -h, --help               print this help screen

    Valid TIME format:
        (1) 1234 [s|sec|secs|seconds]
        (2) 1:02:03.456
        (3) 1 hour 2 minute 3 second 456 millis
    For (2) and (3), at least one part among four is specified.
EO_USAGE
    exit 0 unless defined($_[0]);
    1;
}

sub interpret_time {
    my ($t) = @_;
    if ($t =~ /^\s*(\d+)\s*(?:second|seconds|sec|secs|s)\s*$/) { # simple seconds
        return $1;
    } elsif ( # 3h4m5s format
        $t =~ /^\s*
            (?: (\d+)\s*(?:hour|hr|h|:) )?
            (?: (\d+)\s*(?:minute|min|m|:) )?
            (?: (\d+)\s*(?:second|sec|s)? )?
            (?: [:.]?\s*(\d+)\s*(?:ms|millis)? )?
        \s*$/xo) {
        return undef unless (grep(defined, ($1, $2, $3, $4)) > 0);
        my $hour   = $1 || 0;
        my $min    = $2 || 0;
        my $sec    = $3 || 0;
        my $millis = $4 || 0;
        return sprintf("%d.%s", $hour * 3600 + $min * 60 + $sec, $millis);
    }
    return undef;
}

sub secs_to_time {
    my ($num) = @_;
    my $millis = 0;
    if ($num =~ /(\.\d+)$/) {
        $millis = $1;
    }
    my $hour = int($num / 3600);
    $num %= 3600;
    my $min = int($num / 60);
    $num %= 60;
    return sprintf ("%d:%02d:%02d.%03d", $hour, $min, $num, $millis);
}

sub time_to_secs {
    my ($str) = @_;
    if ($str =~ /^(?:\d+:)?(?:\d\d?:)?(?:\d\d?)(?:\.\d+)?$/) {
        $str =~ s/\.\d+$//; # milliseconds is ignored
        my @parts = split ':', $str;
        my $total_secs = 0;
        my $exponent = 1;
        for my $i (reverse(0 .. $#parts)) {
            $total_secs += $parts[$i] * $exponent;
            $exponent *= 60;
        }
        return $total_secs;
    }
    die "ERROR: $str: unknown format";
}

sub error {
    my $exit_status = shift;
    my ($package, $filename, $line, $subroutine) = caller();
    $subroutine = 'main' unless defined($subroutine);
    print STDERR "$subroutine: ", @_, "\n";
    print STDERR "from: $filename +$line\n";
    exit $exit_status;
}

